/**
 * Created by ${PRODUCT_NAME}.
 * User: skylerparr
 * Date: 12/27/10
 * Time: 12:01 PM
 * To change this template use File | Settings | File Templates.
 */
package com.thoughtorigin.asset {
import com.thoughtorigin.asset.mock.MockLoaderInfo;
import com.thoughtorigin.loader.AbstractLoader;

import com.thoughtorigin.test.AsyncDispatcher;

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.display.MovieClip;

import flash.display.Sprite;

import flash.events.Event;

import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.utils.ByteArray;
import flash.utils.setTimeout;

import org.flexunit.asserts.assertFalse;
import org.flexunit.asserts.assertNotNull;
import org.flexunit.asserts.assertTrue;
import org.flexunit.async.Async;
import org.mockito.integrations.any;
import org.mockito.integrations.between;
import org.mockito.integrations.callOriginal;
import org.mockito.integrations.given;
import org.mockito.integrations.mock;
import org.mockito.integrations.verify;

[RunWith("org.mockito.integrations.flexunit4.MockitoClassRunner")]
[Mock(type="com.thoughtorigin.loader.AbstractLoader")]
[Mock(type="flash.display.Bitmap")]
[Mock(type="flash.display.Loader")]
[Mock(type="flash.display.BitmapData")]
[Mock(type="flash.display.Sprite")]
[Mock(type="com.thoughtorigin.asset.mock.MockLoaderInfo")]
[Mock(type="flash.utils.ByteArray")]
[Mock(type="flash.events.EventDispatcher")]
public class CloningAssetCacheTest {
    private var _assetCache: TestableCloningAssetCache;

    [Before]
    public function setup(): void {
        _assetCache = new TestableCloningAssetCache();
    }

    [After]
    public function tearDown(): void {
        _assetCache = null;
    }

    [Test]
    public function shouldOnlyCacheAssetOnce(): void {
        var loader: AbstractLoader = mock(AbstractLoader, "", ["url"]);
        var mockLoader: Loader = mock(Loader);
        var bmp: Bitmap = mock(Bitmap, "", [null, "auto", false]);
        var bmpData: BitmapData = mock(BitmapData, "", [10,10,true,Number.NaN]);
        given(loader.url).willReturn("url");
        given(loader.content).willReturn(bmp);

        given(loader.loader).willReturn(mockLoader);
        given(mockLoader.content).willReturn(bmp);
        given(bmp.bitmapData).willReturn(bmpData);
        given(bmpData.clone).willReturn(new BitmapData(10,10,true,Number.NaN));

        assertFalse(_assetCache.isAssetCached("url"));
        _assetCache.cacheAsset(loader);
        _assetCache.cacheAsset(loader);
        assertTrue(_assetCache.isAssetCached("url"));

        verify(between(1,1)).that(loader.content);
    }

    [Test]
    public function shouldCloneBitmapAndDestoryLoader(): void {
        var loader: AbstractLoader = mock(AbstractLoader, "", ["url"]);
        var mockLoader: Loader = mock(Loader);
        var bmp: Bitmap = mock(Bitmap, "", [null, "auto", false]);
        var bmpData: BitmapData = mock(BitmapData, "", [10,10,true,Number.NaN]);
        given(loader.url).willReturn("url");
        given(loader.content).willReturn(bmp);

        given(loader.loader).willReturn(mockLoader);
        given(mockLoader.content).willReturn(bmp);
        given(bmp.bitmapData).willReturn(bmpData);
        given(bmpData.clone).willReturn(new BitmapData(10,10,true,Number.NaN));

        _assetCache.cacheAsset(loader);

        verify(between(1,1)).that(loader.content);
        verify(between(1,1)).that(loader.loader);
        verify(between(1,1)).that(mockLoader.unloadAndStop);
        verify(between(1,1)).that(bmpData.clone);
    }

    [Test(async)]
    public function shouldCloneSwfAndDestoryLoader(): void {
        var loader: AbstractLoader = mock(AbstractLoader, "", ["url"]);
        var mockLoader: Loader = mock(Loader);
        var sprite: Sprite = mock(Sprite);
        var obj: MockLoaderInfo = mock(MockLoaderInfo);
        var bytes: ByteArray = mock(ByteArray);
        given(loader.url).willReturn("url");
        given(loader.content).willReturn(sprite);

        given(loader.loader).willReturn(mockLoader);
        given(mockLoader.content).willReturn(sprite);
        given(loader.contentDispatcher).willReturn(obj);
        given(obj.bytes).willReturn(bytes);

        var _mockLoader: Loader = mock(Loader);
        var _dispatcher: EventDispatcher = mock(EventDispatcher);
        given(_dispatcher.dispatchEvent(any())).will(callOriginal());
        given(_dispatcher.addEventListener(any(), any())).will(callOriginal());
        given(_mockLoader.loadBytes(any())).will(new EventAnswer(_dispatcher, new Event(Event.COMPLETE)))
        given(_mockLoader.content).willReturn(sprite);

        _assetCache._dispatcher = _dispatcher;
        _assetCache._loader = _mockLoader;

        _assetCache.cacheAsset(loader);

        var callback: Function = function(): void {
            verify(between(1,1)).that(loader.content);
            verify(between(2,2)).that(loader.loader);
            verify(between(1,1)).that(mockLoader.unloadAndStop());
            verify(between(1,1)).that(obj.bytes);

            var d: AsyncDispatcher = new AsyncDispatcher();
            d.addEventListener(Event.COMPLETE, async);
            d.doDispatch();
        }

        var async: Function = Async.asyncHandler(this, function(e: Event, o: Object): void {
            assertTrue(true);
        }, 200);

        setTimeout(callback, 100);
    }

    [Test]
    public function shouldBeAbleToDeleteAnAsset(): void {
        var loader: AbstractLoader = mock(AbstractLoader, "", ["url"]);
        var mockLoader: Loader = mock(Loader);
        var bmp: Bitmap = mock(Bitmap, "", [null, "auto", false]);
        var bmpData: BitmapData = mock(BitmapData, "", [10,10,true,Number.NaN]);
        given(loader.url).willReturn("url");
        given(loader.content).willReturn(bmp);

        given(loader.loader).willReturn(mockLoader);
        given(mockLoader.content).willReturn(bmp);
        given(bmp.bitmapData).willReturn(bmpData);
        given(bmpData.clone).willReturn(new BitmapData(10,10,true,Number.NaN));

        assertFalse(_assetCache.isAssetCached("url"));
        _assetCache.cacheAsset(loader);
        assertTrue(_assetCache.isAssetCached("url"));

        verify(between(1,1)).that(loader.content);

        _assetCache.deleteAsset("url");

        assertFalse(_assetCache.isAssetCached("url"));
    }

    [Test(async)]
    public function shouldBeAbleToGeCachedAsset(): void {
        var loader: AbstractLoader = mock(AbstractLoader, "", ["url"]);
        var mockLoader: Loader = mock(Loader);
        var bmp: Bitmap = mock(Bitmap, "", [null, "auto", false]);
        var bmpData: BitmapData = mock(BitmapData, "", [10,10,true,Number.NaN]);
        given(loader.url).willReturn("url");
        given(loader.content).willReturn(bmp);

        given(loader.loader).willReturn(mockLoader);
        given(mockLoader.content).willReturn(bmp);
        given(bmp.bitmapData).willReturn(bmpData);
        given(bmpData.clone).willReturn(new BitmapData(10,10,true,Number.NaN));

        assertFalse(_assetCache.isAssetCached("url"));
        _assetCache.cacheAsset(loader);
        assertTrue(_assetCache.isAssetCached("url"));

        verify(between(1,1)).that(loader.content);

        var async: Function = Async.asyncHandler(this, function(e: Event, o: Object): void {
            assertTrue(true);
        }, 200);

        _assetCache.getAsset("url", function(bmp1: DisplayObject): void {
            _assetCache.getAsset("url", function(bmp2: DisplayObject): void {
                assertNotNull(bmp1);
                assertNotNull(bmp2);

                assertFalse(bmp1 == bmp2);

                var d: AsyncDispatcher = new AsyncDispatcher();
                d.addEventListener(Event.COMPLETE, async);
                d.doDispatch();
            });
        });
    }
}
}

import com.thoughtorigin.asset.CloningAssetCache;

import flash.display.Loader;
import flash.events.IEventDispatcher;

class TestableCloningAssetCache extends CloningAssetCache {

    public var _loader: Loader;
    public var _dispatcher: IEventDispatcher;

    override protected function createLoader():Loader {
        return _loader;
    }

    override protected function getLoaderInfo(loader:Loader):IEventDispatcher {
        return _dispatcher;
    }
}

import flash.events.Event;

import flash.utils.setTimeout;

import org.mockito.api.Answer;

class EventAnswer implements Answer {

    private var _dispatcher: IEventDispatcher;
    private var _eventToDispatch: Event;

    public function EventAnswer(dispatcher: IEventDispatcher, eventToDispatch: Event) {
        _dispatcher = dispatcher
        _eventToDispatch = eventToDispatch;
    }

    public function give():* {
        setTimeout(function(): void {
            _dispatcher.dispatchEvent(_eventToDispatch);
        }, 20);
    }
}
